package com.wlyuan.open.scanner.repository.impl;

import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wlyuan.open.scanner.assembler.ScannerOrderAssembler;
import com.wlyuan.open.scanner.constant.Constants;
import com.wlyuan.open.scanner.dao.entity.OrderIndexDO;
import com.wlyuan.open.scanner.dao.mapper.OrderIndexMapper;
import com.wlyuan.open.scanner.domain.order.*;
import com.wlyuan.open.scanner.repository.OrderRepository;
import com.wlyuan.open.scanner.utils.DateUtils;
import com.wlyuan.open.scanner.utils.StreamUtils;
import com.wlyuan.open.scanner.utils.enums.order.AttachTypeEnum;
import com.wlyuan.open.scanner.utils.enums.order.OrderExceptionStatusEnum;
import com.wlyuan.open.scanner.utils.enums.order.OrderStatusEnum;
import com.wlyuan.open.scanner.utils.enums.transport.ReceiptTypeEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author lijing
 * @description
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class OrderRepositoryImpl implements OrderRepository {
    private final OrderIndexMapper orderIndexMapper;
    private final BaseOrderRepository baseOrderRepository;

    @Override
    public void sync() {
        logger.info("Index_SrcClass = 1 and Index_SrcOrderID = 0 and Index_Status <> -1 and Index_Status <> 0");
        var count = orderIndexMapper.count();
        logger.info("订单老数据数据量，size：{}", count);
        var pages = (int) Math.ceil(count * 1.0 / Constants.PAGE_SIZE);
        for (int i = 1; i <= pages; i++) {
            logger.info("开始同步订单：第{}页，共{}页", i, pages);
            var list = orderIndexMapper.getOrderIds(i, Constants.PAGE_SIZE);
            list.forEach(id -> {
                try {
                    var data = orderIndexMapper.getById(id);
                    if (Constants.ORDER_TENANT.contains(data.getIndexCreatorcompanyid())) {
                        logger.error("订单id：{},租户id:{}", id, data.getIndexCreatorcompanyid());
                        baseOrderRepository.sync(null);
                    } else {
                        process(data);
                        baseOrderRepository.sync(ScannerOrderAssembler.assemble(OrderConvert.convert(data)));
                    }

                } catch (Exception e) {
                    logger.error("订单同步异常：{}，{}", id, e);
                }
            });
        }
        logger.info("订单同步完成......");
    }

    @Override
    public List<Order> list() {
        return Collections.emptyList();
    }

    @Override
    public Order getById(Long orderId) {
        return Optional.ofNullable(orderId).map(id -> {
            var data = orderIndexMapper.getOrderById(id);
            if (Constants.ORDER_TENANT.contains(data.getIndexCreatorcompanyid())) {
                return null;
            }
            return Optional.ofNullable(data).map(order -> {
                process(order);
                return OrderConvert.convert(order);
            }).orElse(null);

        }).orElse(null);
    }

    @Override
    public void getByTenantId(Long tenantId) {
        var count = orderIndexMapper.countByTenantId(tenantId);
        logger.info("租户{}订单老数据数据量，size：{}", tenantId, count);
        var pages = (int) Math.ceil(count * 1.0 / Constants.PAGE_SIZE);
        for (int i = 1; i <= pages; i++) {
            logger.info("开始同步租户{}订单：第{}页，共{}页", tenantId, i, pages);
            var list = orderIndexMapper.getOrderIdsByTenantId(i, Constants.PAGE_SIZE, tenantId);
            list.forEach(id -> {
                try {
                    var data = orderIndexMapper.getById(id);
                    process(data);
                    baseOrderRepository.sync(ScannerOrderAssembler.assemble(OrderConvert.convert(data)));
                } catch (Exception e) {
                    logger.error("订单同步异常：{}，{}", id, e);
                }
            });
        }
        logger.info("{}订单同步完成......", tenantId);
    }

    @Override
    public Order getOrderByOrderId(Long orderId) {
        LambdaQueryWrapper<OrderIndexDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderIndexDO::getIndexId, orderId);
        var data = orderIndexMapper.selectOne(queryWrapper);
        return OrderConvert.convert(data);
    }

    @Override
    public Long getOrderSrcClass(Long orderId) {
        return Optional.ofNullable(orderId).map(id -> {
            return orderIndexMapper.getSrcClassById(id);
        }).orElse(null);
    }

    @Override
    public void process(OrderIndexDO data) {
        var orderId = data.getIndexId();
        //地址
        baseOrderRepository.processAddress(data);
        //是否场景证书
        baseOrderRepository.cert(data);
        //签单人
        baseOrderRepository.sign(data, false);
        //回单人
        baseOrderRepository.receipt(data, false);
        //关单人
        baseOrderRepository.close(data);
        //补差
        baseOrderRepository.valueAddition(data);
        //多段轨迹
        data.setTransports(baseOrderRepository.getOrderAdditionTransport(orderId, data.isAdditionTransportType()));
        //物品
        var orderGoodsList = baseOrderRepository.getOrderGoodsByOrderId(orderId, data.getIndexCreatorcompanyid());
        data.setGoodsList(orderGoodsList);
        //定制
        customize(data);
        //实签总数 和 异签总数
        signQuantity(data, orderGoodsList);
        //回单总数和 回单异常总数
        receiptQuantity(data, orderGoodsList);
        //附件
        data.setAttachment(baseOrderRepository.attach(orderId, data.getSignType()));
        //异常状态
        exceptionStatus(data);
        //时效天数
        processDays(data);
    }

    @Override
    public List<Long> getOrderIdByTime(String startTime, String endTime) {
        return orderIndexMapper.getOrderIdByTime(startTime, endTime);
    }

    @Override
    public List<Long> getOrderIdByTenantIdTime(Long tenantId, String startTime, String endTime) {
        return orderIndexMapper.getOrderIdByTenantIdTime(tenantId, startTime, endTime);
    }

    private void signQuantity(OrderIndexDO order, List<OrderGoods> list) {
        order.setSignQuantity(BigDecimal.ZERO.intValue());
        order.setSignExceptionQuantity(BigDecimal.ZERO.intValue());
        if (!CollectionUtils.isEmpty(list)) {
            var signList = list.stream().map(OrderGoods::getGoodsSign).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(signList)) {
                if (Constants.KING_TENANT.equals(order.getIndexCreatorcompanyid())) {
                    order.setSignQuantity(StreamUtils.sum(list, OrderGoods::getQuantity));
                    order.setSignExceptionQuantity(BigDecimal.ZERO.intValue());
                } else {
                    order.setSignQuantity(StreamUtils.sum(signList, OrderSign::getQuantity));
                    order.setSignExceptionQuantity(StreamUtils.sum(signList, OrderSign::getExceptionQuantity));
                }
            }
        }

    }

    private void customize(OrderIndexDO order) {
        //奇正延期原因
        try {
            if (Constants.QZ_TENANT.equals(order.getIndexCreatorcompanyid()) && !CollectionUtils.isEmpty(order.getGoodsList())) {
                Optional.ofNullable(order.getGoodsList().stream().findFirst().orElse(null)).ifPresent(orderGoods -> {
                    if (StringUtils.isNotBlank(orderGoods.getComments()) && orderGoods.getComments().contains(Constants.QZ_DELAY_REASON)) {
                        String[] comments = orderGoods.getComments().split(Constants.QZ_DELAY_REASON);
                        if (comments != null && comments.length > 1 && StringUtils.isNumeric(comments[1])) {
                            order.setDelayReason(Integer.valueOf(comments[1]));
                        }
                    }
                });
            }
        } catch (Exception e) {
            logger.error("奇正定制延期原因出错：{}", order.getIndexId());
            e.printStackTrace();
        }
    }

    private void receiptQuantity(OrderIndexDO order, List<OrderGoods> list) {
        order.setReceiptQuantity(BigDecimal.ZERO.intValue());
        order.setReceiptExceptionQuantity(BigDecimal.ZERO.intValue());
        if (!CollectionUtils.isEmpty(list)) {
            var receiptList = list.stream().map(OrderGoods::getGoodsReceipt).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(receiptList)) {
                if (Constants.KING_TENANT.equals(order.getIndexCreatorcompanyid())) {
                    order.setReceiptQuantity(StreamUtils.sum(list, OrderGoods::getQuantity));
                    order.setReceiptExceptionQuantity(BigDecimal.ZERO.intValue());
                } else {
                    order.setReceiptQuantity(StreamUtils.sum(receiptList, OrderReceipt::getQuantity));
                    order.setReceiptExceptionQuantity(StreamUtils.sum(receiptList, OrderReceipt::getExceptionQuantity));
                }
            }
        }
    }

    private void exceptionStatus(OrderIndexDO order) {
        var attach = order.getAttachments();
        //签收异常数大于0
        if (order.getSignExceptionQuantity() > 0) {
            order.addException(OrderExceptionStatusEnum.SIGN_EXCEPTION.getValue());
        }
        if (!CollectionUtils.isEmpty(attach)) {
            //回单照片 附件
            var list = StreamUtils.filter(attach, a -> AttachTypeEnum.RECEIPT.equals(a.getType()));
            if (!CollectionUtils.isEmpty(list)) {
                order.addException(OrderExceptionStatusEnum.RECEIPT_PHOTO.getValue());
            }
        }
        //回单丢失
        if (ReceiptTypeEnum.isLost(order.getIndexReceipttype())) {
            order.addException(OrderExceptionStatusEnum.RECEIPT_LOSE.getValue());
        }
        //补单
        if (ReceiptTypeEnum.isReplenish(order.getIndexReceipttype())) {
            order.addException(OrderExceptionStatusEnum.REPLACEMENT_ORDER.getValue());
        }
        //订单关闭
        if (OrderStatusEnum.isClose(order.getIndexStatus())) {
            order.addException(OrderExceptionStatusEnum.CLONE_ORDER.getValue());
        }
        //回单复核：签收数和回单数不一致  或者 签收异常数 和 回单异常数不一致
        if (order.getSignQuantity().compareTo(order.getReceiptQuantity()) != 0 || order.getSignExceptionQuantity().compareTo(order.getReceiptExceptionQuantity()) != 0) {
            order.addException(OrderExceptionStatusEnum.RECEIPT_RECHECK.getValue());
        }
    }

    private void processDays(OrderIndexDO data) {
        Integer days = DateUtils.toDays(data.getIndexFromtime(), data.getIndexTotime());
        data.setDays(days);
    }

}
